home *** CD-ROM | disk | FTP | other *** search
- ******************************************************************
- * COPYRIGHT (C) 1986 by Donald Krantz and James Stanley
- * - Note: This is a real, live, actual, registered copyright,
- * and should be treated as such. This source code is from
- * the book "68000 Assembly Language", Krantz and Stanley,
- * Addison-Wesley Publishing Company, Reading, MA, 1986.
- *
- * Permission granted by the authors for non-commercial use
- * in programs released to the public domain, as long as this
- * copyright notice remains attached and visible.
- *
- *****************************************************************
- * Editor Dispatcher
-
- xref prtscr,stats,_getkey,sync_curs,case,cursor
- xref _keyhit,group_1,group_2,group_4,refind,errors
- xref prompt
- xdef up,down,right,left,down_page,up_page,del_left
- xdef toggle,eol,sol,dirty
- xdef edit
-
- #edit.h
- #cursor.h
-
- ****************************************************************
- * EDIT - Main editor dispatcher and executive.
- edit:
- bsr _keyhit * see if we're busy
- tst.w d0 * d0 is nonzero if we're busy
- bne sk1exec * we skip refresh if busy
- bsr align_scr * make sure cursor's on screen
- bsr prtscr * Print current buffer
- bsr stats * Print editing stats
- move.w ed_err(a5),d0 * Get edit error flag
- ext.l d0 * make into longword
- lsl.l #2,d0 * multiply by four
- move.l #errors,a0 * get error message lookup table
- add.l d0,a0 * get offset
- move.l (a0),a0 * get error string address
- bsr prompt * output message (or blank old)
- clr.w ed_err(a5) * mark "no errors"
- sk1exec:
- move.w scr_row(a5),-(a7) put cursor where it belongs
- move.w scr_col(a5),-(a7)
- bsr cursor
- addq.l #4,a7 * adjust stack
- bsr sync_curs * Put cursor where it belongs
- bsr _getkey * get input
- ext.w d0 * make into a word
- move.l #dispatch,a0 * load up case table
- bsr case * perform required operation
-
- bra edit * repeat
- *****************************************************************
- * Top Level Editor Dispatch Table
- dispatch:
- dc.w 23 * Number of valid options
- dc.w tab * Tab
- dc.l in_chr
- dc.w 0 * PC cursor key prefix
- dc.l group_4
- dc.w c_up * Cursor up one line
- dc.l up
- dc.w c_down * Cursor down one line
- dc.l down
- dc.w c_right * Cursor one char right
- dc.l right
- dc.w c_left * Cursor one char left
- dc.l left
- dc.w c_w_right * Cursor one word right
- dc.l w_right
- dc.w c_w_left * Cursor one word left
- dc.l w_left
- dc.w return * Return Key
- dc.l ret
- dc.w backsp * Backspace Key
- dc.l left
- dc.w left_del * Left Delete Character
- dc.l del_left
- dc.w right_del * Right Delete Character
- dc.l del_right
- dc.w lit_prefix * Literal Insertion Prefix
- dc.l prefix
- dc.w word_del * Right Delete Word
- dc.l del_word
- dc.w group1 * Group 1 Commands prefix
- dc.l group_1
- dc.w group2 * Group 2 Commands prefix
- dc.l group_2
- dc.w group3 * Group 3 Commands prefix
- dc.l group_3
- dc.w line_del * Delete line key
- dc.l del_line
- dc.w page_up * Page Up key
- dc.l up_page
- dc.w page_down * Page Down key
- dc.l down_page
- dc.w repeat * Repeat Find key
- dc.l refind
- dc.w insert_key * Insert Toggle Key
- dc.l toggle
- dc.w ins_line * Insert Line key
- dc.l line_ins
- dc.l ins_chr * default - insert character
- *****************************************************************
- * GROUP_3 - group 3 (window) commands
- group_3:
- move.l #-1,d0 * Set "continue" flag
- addq.l #4,a7 * lift one return address
- rts * return to caller of "edit"
- *****************************************************************
- * RIGHT - Moves cursor right. Returns byte moved in D0.
- right:
- clr.w d0 * setup fake return value
- move.l e_gap(a5),a0 * check if we can move left
- cmp.l e_buf(a5),a0 * we look at the end of buffer
- bgt sk0_rt * jump if we can't move
- move.l b_gap(a5),a1 * get destination for char
- move.b (a0),d0 * save the byte to return it
- cmp.b #10,(a0) * check for line crossing
- bne sk1_rt * skip if not line crossing
- addq.w #1,log_lin(a5) * add one to line count
- sk1_rt:
- move.b (a0)+,(a1)+ * move the byte across gap
- addq.l #1,e_gap(a5) * move end pointer
- addq.l #1,b_gap(a5) * move start pointer
- sk0_rt:
- rts
- *****************************************************************
- * LEFT - moves cursor left. Returns byte moved in D0.
- left:
- clr.w d0 * setup fake return value
- move.l b_gap(a5),a0 * check if we can move right
- cmp.l b_buf(a5),a0 * we look at the start of buffer
- ble sk0_lf * jump if we can't move
- move.l e_gap(a5),a1 * get destination for char
- move.b -(a0),-(a1) * move the byte across gap
- move.b (a1),d0 * save the byte to return it
- cmp.b #10,(a1) * check for line crossing
- bne sk1_lf * jump if not line crossing
- subq.w #1,log_lin(a5) * bump down current line counter
- sk1_lf:
- subq.l #1,e_gap(a5) * move end pointer
- subq.l #1,b_gap(a5) * move start pointer
- sk0_lf:
- rts
- *****************************************************************
- * UP - moves cursor up one line
- up:
- bsr sol * move to start of this line
- bsr left * move back over newline
- bsr sol * move to start of this line
- bsr outline * put cursor out into line
- rts
- *****************************************************************
- * DOWN - moves cursor down one line
- down:
- bsr eol * move to end of line
- bsr right * jump over newline
- bsr outline * put cursor out into line
- rts
- *****************************************************************
- * W_RIGHT - Moves the cursor one word right
- w_right:
- bsr right * start right
- tst.b d0 * look for end-of-file
- beq sk0_wr * outta here if end of file
- bsr isdelim * look for delimiter
- tst.b d0 * check return value
- beq w_right * loop until we find delimiter
- lp0_wr:
- bsr right * start right
- tst.b d0 * look for end-of-file
- beq sk0_wr * outta here if end of file
- bsr isdelim * look for delimiter
- tst.b d0 * check return value
- bne lp0_wr * loop until we finish delimiters
- bsr left * back off one
- sk0_wr:
- rts
- *****************************************************************
- * W_LEFT - move the cursor one word to the left
- w_left:
- bsr left * start left
- tst.b d0 * look for start-of-file
- beq sk0_wl * outta here if start of file
- bsr isdelim * look for delimiter
- tst.b d0 * check return value
- bne w_left * loop while no delimiter
- lp0_wl:
- bsr left * start left
- tst.b d0 * look for start-of-file
- beq sk0_wl * outta here if start of file
- bsr isdelim * look for delimiter
- tst.b d0 * check return value
- beq lp0_wl * loop until we hit delimiters
- bsr right * back off one
- sk0_wl:
- rts
- *****************************************************************
- * UP_PAGE - moves cursor up one page
- up_page:
- move.w w_rows(a5),d1 * calculate number of lines
- subq.w #2,d1 * leave two rows for context
- bgt sk0_up * check if we still have some
- clr.w d1 * we need at least one...
- sk0_up:
- bsr sol * move to start of this line
- bsr left * back up over newline
- tst.w d0 * check for top of file
- beq sk1_up * break out if top of file
- dbra d1,sk0_up * loop 'lines' times
- bsr right * move over current newline
- sk1_up:
- bsr outline * move cursor out into line
- rts
- *****************************************************************
- * DOWN_PAGE - moves cursor down one page
- down_page:
- move.w w_rows(a5),d1 * calculate number of lines
- subq.w #3,d1 * leave two rows for context
- bgt sk0_dn * check if we still have some
- move.w #0,d1 * we need at least one...
- sk0_dn:
- bsr eol * move to end of this line
- bsr right * skip over newline
- dbra d1,sk0_dn * loop 'lines' times
- bsr sol * move to start of this line
- bsr outline * move cursor out into line
- rts
- *****************************************************************
- * DEL_RIGHT - delete one character to the right
- del_right:
- bsr right * try to move right
- tst.b d0 * is there anything there?
- beq sk0dr * jump if not
- subq.l #1,b_gap(a5) * delete character
- bsr dirty * set modified flags
- sk0dr:
- rts
- *****************************************************************
- * DEL_LEFT - delete one character to the left
- del_left:
- bsr left * try to move left
- tst.b d0 * is there anything there?
- beq sk0dl * jump if not
- addq.l #1,e_gap(a5) * delete character
- bsr dirty * set modified flags
- sk0dl:
- rts
- *****************************************************************
- * DEL_LINE - deletes line that cursor is on
- del_line:
- bsr sol * move to start of this line
- move.l b_gap(a5),-(a7) * save gap start address
- bsr eol * move to end of this line
- bsr right * and one more for newline
- cmp.b #10,d0 * make sure we got a newline
- bne sk0ld * jump if not
- subq.w #1,log_lin(a5) * adjust line count
- sk0ld:
- move.l (a7)+,b_gap(a5) * poof! line's gone.
- bsr dirty * set modified flags
- rts
- *****************************************************************
- del_word:
- move.l b_gap(a5),-(a7) * Save gap pointer
- bsr w_right * move cursor one word right
- move.l (a7)+,b_gap(a5) * restore pointer, word vanishes
- bsr dirty * set modified flags
- rts
- *****************************************************************
- * PREFIX - Allows human to inser next char typed as literal
- prefix:
- bsr _getkey * take the next keystroke as-is
- bra in_chr * insert whatever comes in
- *****************************************************************
- ret:
- move.b #10,d0 * load up a newline
- bra in_chr * go insert it
- *****************************************************************
- toggle:
- not.w insert(a5) * complement insert toggle
- rts
- *****************************************************************
- line_ins:
- move.l e_gap(a5),a0 * get begin gap pointer
- cmp.l b_gap(a5),a0 * see if there's room
- ble sk0_lns * jump if no room
- move.b #10,-(a0) * put in newline
- subq.l #1,e_gap(a5) * adjust end pointer
- bsr dirty * set modified flags
- rts * exit
- sk0_lns:
- move.w #2,ed_err(a5) * error 2 - no more room
- rts
- *****************************************************************
- ins_chr:
- cmp.b #$20,d0 * check if char out of range
- blt sk1_ins * if out, goto error
- in_chr:
- tst.w insert(a5) * is insert toggle on?
- bne sk2_ins * jump if yes
- move.l e_gap(a5),a0 * get end-of-gap address
- cmp.l e_buf(a5),a0 * check if at end of buffer
- bgt sk2_ins * yes, go insert
- cmp.b #10,(a0) * see if next char is newline
- beq sk2_ins * yes, go insert
- move.l b_gap(a5),a0 * we need to replace...
- move.b d0,(a0) * emplace new character
- addq.l #1,b_gap(a5) * move begin gap pointer
- addq.l #1,e_gap(a5) * move end gap pointer
- bra sk4_ins * exit
- sk2_ins:
- move.l b_gap(a5),a0 * get begin gap pointer
- cmp.l e_gap(a5),a0 * look see if there's room
- bge sk3_ins * jump if no room
- move.b d0,(a0) * insert character
- addq.l #1,b_gap(a5) * move gap pointer
- cmp.b #10,d0 * check for newline
- bne sk4_ins * skip if not
- addq.w #1,log_lin(a5) * increment logical line count
- sk4_ins:
- bsr dirty * set modified flags
- rts * That's it.
- sk1_ins:
- move.w #1,ed_err(a5) * error #1 - char out of range
- rts
- sk3_ins:
- move.w #2,ed_err(a5) * error #2 - no room
- rts
- *****************************************************************
- * ISDELIM - returns TRUE if char in D0 matches delimiter list
- isdelim:
- move.l #delim,a0 * get delimiter list address
- move.w #d_cnt,d1 * get delimiter count
- lp0_dm:
- cmp.b (a0)+,d0 * look for a match
- beq d_true * found one, jump out
- dbra d1,lp0_dm * check all cases
- clr.w d0 * return FALSE
- rts
- d_true:
- move.w #$FFFF,d0 * return TRUE
- rts
-
- delim: dc.b 9,10,' ,.-+/><()'
- d_cnt equ *-delim
- dc.w 0
- *****************************************************************
- * SOL - moves cursor to start of line
- sol:
- bsr left * try one char back
- tst.b d0 * check if at top of file
- beq sk0sol * jump out if at top of file
- cmp.b #10,d0 * is this a newline?
- bne sol * back up to start of this line
- bsr right * re-adjust cursor
- sk0sol:
- rts
- *****************************************************************
- * EOL - moves cursor to end of line
- eol:
- bsr right * try one char forward
- tst.b d0 * check if at end of file
- beq sk0eol * jump out if at end of file
- cmp.b #10,d0 * check for newline
- bne eol * loop if not newline
- bsr left * put cursor behind newline
- sk0eol:
- rts
- *****************************************************************
- * OUTLINE - moves cursor to current logical column
- outline:
- clr.w d2 * d2 is column accumulator
- lp0_ol:
- bsr right * try to move right
- tst.b d0 * check if end-of file
- beq sk1_ol * exit if end-of-file
- cmp.b #10,d0 * check for end of line
- beq sk0_ol * done if end-of-line
- addq.w #1,d2 * start with one column
- cmp.b #$20,d0 * see if control char
- bge sk2_ol * if not, we're done with char
- cmp.b #tab,d0 * is char a tab?
- beq sk3_ol * jump if tab
- subq.l #1,d2 * take away column for ctrl char
- bra sk2_ol * make loop test
- sk3_ol:
- move.w d2,d0 * make a copy of column count
- and.w #$0007,d0 * check for correct tab column
- beq sk2_ol * if so, make loop test
- addq.w #1,d2 * otherwise, add one space to col
- bra sk3_ol * and keep expanding tab
- sk2_ol:
- cmp.w log_col(a5),d2 * are we far enough out?
- ble lp0_ol * no, keep trying
- sk0_ol:
- bsr left * back up to correct position
- sk1_ol:
- rts
- *****************************************************************
- * ALIGN_SCR - Handles vertical cursor alignment. Puts the cursor
- * on the screen if it's off.
- align_scr:
- move.l b_gap(a5),a0 * Get start of gap (cursor loc.)
- cmp.l top_lef(a5),a0 * see if cursor's off top
- bge sk0_as * jump if not off the top
- lp0_as:
- subq.l #1,a0 * start backing off
- cmp.l b_buf(a5),a0 * don't go under start of file
- beq sk1_as * jump if at start of file
- cmp.b #10,(a0) * look for newline
- bne lp0_as * not newline, try again
- addq.l #1,a0 * ok, move past newline
- sk1_as:
- cmp.l b_buf(a5),a0 * one last check for nasties
- bge sk5_as * no nasties
- move.l b_buf(a5),a0 * start at top
- sk5_as:
- move.l a0,top_lef(a5) * reset top of screen
- bra sk3_as * exit
- sk0_as:
- sub.l top_lef(a5),a0 * A0 is now chars-to-cursor
- move.l a0,d0 * we need count in data register
- move.l top_lef(a5),a0 * A0 is where we start looking
- clr.w d1 * d1 will be newline count
- bra sk2_as * do loop test before check
- lp1_as:
- cmp.b #10,(a0)+ * look for newlines
- bne sk2_as * if not newline, don't care
- addq.w #1,d1 * if newline, increment count
- sk2_as:
- dbra d0,lp1_as * loop test
- sub.w w_rows(a5),d1 * see if more newlines than rows
- blt sk3_as * if not, we're ok
- move.l top_lef(a5),a0 * get starting point
- lp3_as:
- cmp.b #10,(a0)+ * we need to skip newlines
- bne lp3_as * if not newline, we don't care
- sk4_as:
- dbra d1,lp3_as * loop for (d1+1) newlines
- move.l a0,top_lef(a5) * save new top left corner
- sk3_as:
- rts
-
- end